import { ScrollView, v2, Vec3 } from "cc";

const EPSILON = 1e-4;
const OUT_OF_BOUNDARY_BREAKING_FACTOR = 0.05;

let myEaseOut = function (time) {
    time -= 1;
    return (Math.pow(time, 9) + 1);
};

export function optimizeScrollView(_scrollView: ScrollView) {
    /**
         * 属性检查器中，break 参数设置为0.9以上比较合适，否则太快
         */
    // let scrollView: any = (<any>this.scrollView);
    let scrollView: any = _scrollView as any;
    scrollView._startInertiaScroll = (touchMoveVelocity: Vec3) => {
        const inertiaTotalMovement = new Vec3(touchMoveVelocity);
        inertiaTotalMovement.multiplyScalar(10);
        scrollView._startAttenuatingAutoScroll(inertiaTotalMovement, touchMoveVelocity);
    };
    scrollView._processAutoScrolling = (dt) => {
        let isAutoScrollBrake = scrollView._isNecessaryAutoScrollBrake();
        let brakingFactor = isAutoScrollBrake ? OUT_OF_BOUNDARY_BREAKING_FACTOR : 1;
        scrollView._autoScrollAccumulatedTime += dt * (1 / brakingFactor);

        let percentage = Math.min(1, scrollView._autoScrollAccumulatedTime / scrollView._autoScrollTotalTime);
        if (scrollView._autoScrollAttenuate) {
            percentage = myEaseOut(percentage);
        }

        const clonedAutoScrollTargetDelta = scrollView._autoScrollTargetDelta.clone();
        clonedAutoScrollTargetDelta.multiplyScalar(percentage);
        const clonedAutoScrollStartPosition = scrollView._autoScrollStartPosition.clone();
        clonedAutoScrollStartPosition.add(clonedAutoScrollTargetDelta);
        let reachedEnd = Math.abs(percentage - 1) <= EPSILON;

        const fireEvent = Math.abs(percentage - 1) <= scrollView.getScrollEndedEventTiming();
        if (fireEvent && !scrollView._isScrollEndedWithThresholdEventFired) {
            scrollView._dispatchEvent('scroll-ended-with-threshold');
            scrollView._isScrollEndedWithThresholdEventFired = true;
        }

        if (scrollView.elastic) {
            const brakeOffsetPosition = clonedAutoScrollStartPosition.clone();
            brakeOffsetPosition.subtract(scrollView._autoScrollBrakingStartPosition);
            if (isAutoScrollBrake) {
                brakeOffsetPosition.multiplyScalar(brakingFactor);
            }
            clonedAutoScrollStartPosition.set(scrollView._autoScrollBrakingStartPosition);
            clonedAutoScrollStartPosition.add(brakeOffsetPosition);
        } else {
            const moveDelta = clonedAutoScrollStartPosition.clone();
            moveDelta.subtract(scrollView.getContentPosition());
            const outOfBoundary = scrollView._getHowMuchOutOfBoundary(moveDelta);
            if (!outOfBoundary.equals(Vec3.ZERO, EPSILON)) {
                clonedAutoScrollStartPosition.add(outOfBoundary);
                reachedEnd = true;
            }
        }

        if (reachedEnd) {
            scrollView._autoScrolling = false;
        }

        let deltaMove = clonedAutoScrollStartPosition.clone();
        deltaMove.subtract(scrollView._getContentPosition());
        scrollView._clampDelta(deltaMove)
        scrollView._moveContent(deltaMove, reachedEnd);
        scrollView._dispatchEvent('scrolling');
        scrollView.deltaMove = deltaMove;

        // scollTo API controll move
        if (!scrollView._autoScrolling) {
            scrollView._isBouncing = false;
            scrollView._scrolling = false;
            scrollView._dispatchEvent('scroll-ended');
        }
    }
}